package com.taobao.protobuf.popmenu;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;

import com.taobao.protobuf.Activator;

public class PBGeneratorDelegate /*extends Action **/implements IObjectActionDelegate {

	private String type = null;
	
	IStructuredSelection selection = null;
	
	private final String MARKER_ID = Activator.PLUGIN_ID+".pbmarker";
	
	private IWorkbenchPart part = null;

	public PBGeneratorDelegate(String type){
		this.type = type;
	}
	@Override
	public void run(IAction action) {
		
		if(selection != null && !selection.isEmpty()){
			
			save();
			String protocPath = Activator.getDefault().getPreferenceStore().getString("protoc");
			if(protocPath == null || protocPath.length() == 0){
				MessageDialog.openError(part.getSite().getShell(), "Generate sources error", "Can't get protoc path,Set the protoc path  on the perference Page first!");
				return ;
			}
			@SuppressWarnings("rawtypes")
			Iterator ite = selection.iterator();
			List<IFile> files = new ArrayList<IFile>();
			while(ite.hasNext()){
				Object obj = ite.next();
				if(obj instanceof IFile){
					IFile f = (IFile)obj;
					files.add(f);
					generateSingleFile(protocPath, f);
				}
			}
			if(files.size() > 0){
				for(IFile f : files){
					try {
						f.getParent().refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
					} catch (CoreException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
	private void generateSingleFile(String protocPath, IFile f) {
		IContainer container = f.getParent();
		String parent = container.getLocation().toOSString();
		String protoFile = f.getLocation().toOSString();
		String executeCmd = protocPath+" --proto_path="+parent+" "+type+"="+parent+" "+protoFile;
		try {
			Process process = Runtime.getRuntime().exec(executeCmd);
			List<Location> list = processStream(process.getErrorStream(),f);
			if(list != null && list.size() > 0){
				createMarkers(list,f);
			}else{
				try {
					f.deleteMarkers(MARKER_ID, true, IResource.DEPTH_INFINITE);
				} catch (CoreException e1) {
					e1.printStackTrace();
					return ;
				}
			}
			process.destroy();
			
		} catch (IOException e) {
			e.printStackTrace();
		}catch(Exception ex){
			ex.printStackTrace();
		}
	}

	private void save() {
		IWorkbenchPage[] pages = part.getSite().getWorkbenchWindow().getPages();
		for(IWorkbenchPage page : pages){
			page.saveAllEditors(true);
		}
	}
	private void createMarkers(List<Location> list,IFile file) {
		try {
			file.deleteMarkers(MARKER_ID, true, IResource.DEPTH_INFINITE);
		} catch (CoreException e1) {
			e1.printStackTrace();
			return ;
		}
		for(Location location : list){
			IFile f = location.getFile();
			try {
				IMarker marker = f.createMarker(MARKER_ID);
				marker.setAttribute(IMarker.LINE_NUMBER, location.getLine());
				marker.setAttribute(IMarker.MESSAGE, location.getMsg());
				marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
			} catch (CoreException e) {
				e.printStackTrace();
			}
		}
	}
	private List<Location> processStream(InputStream stream ,IFile f) {
		InputStreamReader isreader = new InputStreamReader(stream);
		BufferedReader reader = new BufferedReader(isreader);
		String line = null;
		List<String> lines = new ArrayList<String>();
		try {
			while((line = reader.readLine()) != null){
				lines.add(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		List<Location> locations = new ArrayList<Location>();
		for(String temp : lines){
			if(temp.matches("[^:]*:[0-9]*:[0-9]*:.*")){
				String[] ar = temp.split(":");
				Location location = new Location();
				location.setFile(f);
				try {
					location.setLine(Integer.parseInt(ar[1]));
				} catch (NumberFormatException e) {
					e.printStackTrace();
				}
				location.setMsg(ar[3]);
				locations.add(location);
			}else if(temp.matches("[^:]*:[^:]*")){
				String[] ar = temp.split(":");
				Location location = new Location();
				location.setFile(f);
				location.setMsg(ar[1]);
				locations.add(location);
			}else{
				Location location = new Location();
				location.setFile(f);
				location.setMsg(temp);
				locations.add(location);
			}
		}
		return locations;
	}
	@Override
	public void selectionChanged(IAction action, ISelection selection) {
		if(selection instanceof IStructuredSelection){
			this.selection = (IStructuredSelection)selection;
		}
	}

	@Override
	public void setActivePart(IAction action, IWorkbenchPart targetPart) {
		this.part = targetPart;
	}

//	@Override
//	public void run() {
//		save();
//		String protocPath = Activator.getDefault().getPreferenceStore().getString("protoc");
//		if(protocPath == null || protocPath.length() == 0){
//			MessageDialog.openError(part.getSite().getShell(), "Generate sources error", "Can't get protoc path,Set the protoc path  on the perference Page first!");
//			return ;
//		}
//		generateSingleFile(protocPath, f);
//	}
}
